package com.rzcoding.service;

import com.rzcoding.cache.PermissionCache;
import com.rzcoding.dao.RoleMapper;
import com.rzcoding.dto.base.ResultConst;
import com.rzcoding.dto.resp.PermissionRespMo;
import com.rzcoding.dto.resp.RolePermissionRespMo;
import com.rzcoding.entity.Permission;
import com.rzcoding.entity.Role;
import com.rzcoding.exception.BussinessException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;


@Service
public class AuthService {

    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private PermissionCache permissionCache;

    public Object findPermList(String type) {
        if (type.equalsIgnoreCase("list")) {
            return permissionCache.getPermList();
        }
        if (type.equalsIgnoreCase("tree")) {
            return permissionCache.getTreePermList();
        }
        return null;
    }

    public List<RolePermissionRespMo> findRoleList() {
        return buildRolePerm(null);
    }

    public RolePermissionRespMo findRole(Integer id) {
        List<RolePermissionRespMo> roles = buildRolePerm(id);
        if (CollectionUtils.isEmpty(roles)) {
            return null;
        }
        return roles.get(0);
    }

    public void updateRolePermission(Integer id, String rids) {
        if (StringUtils.isBlank(rids)) {
            return;
        }
        Set<Integer> authIdSet = permissionCache.getPermList().stream().map(Permission::getId).collect(Collectors.toSet());

        StringBuilder sb = new StringBuilder();
        String[] authIds = rids.split(",");
        for (String authId : authIds) {
            if (authIdSet.contains(Integer.parseInt(authId))) {
                sb.append(",").append(authId);
            }
        }
        String authIdsStr = sb.toString();
        if (StringUtils.isBlank(authIdsStr) || ",".equalsIgnoreCase(authIdsStr)) {
            return;
        }

        Role role = new Role();
        role.setId(id);
        role.setAuthIds(authIdsStr);
        roleMapper.updateByPrimaryKeySelective(role);

    }

    public void delRolePermission(Integer id, Integer rightId) {
        Set<Integer> rightIds = new HashSet<>();
        boolean isMatch = false;
        List<PermissionRespMo> treePermList = permissionCache.getTreePermList();
        for (PermissionRespMo levelOnePerm : treePermList) {
            if(isMatch){
                break;
            }
            if (Objects.equals(levelOnePerm.id, rightId)) {
                this.getRightIdsByPermMo(levelOnePerm, rightIds);
                isMatch = true;
            }

            if (CollectionUtils.isNotEmpty(levelOnePerm.children)) {
                for (PermissionRespMo levelTwoPerm : levelOnePerm.children) {
                    if(isMatch){
                        break;
                    }
                    if (Objects.equals(levelTwoPerm.id, rightId)) {
                        this.getRightIdsByPermMo(levelTwoPerm, rightIds);
                        isMatch = true;
                    }

                    if (CollectionUtils.isNotEmpty(levelTwoPerm.children)) {
                        for (PermissionRespMo levelThreePerm : levelTwoPerm.children) {
                            if (Objects.equals(levelThreePerm.id, rightId)) {
                                this.getRightIdsByPermMo(levelThreePerm, rightIds);
                                isMatch = true;
                                break;
                            }
                        }
                    }
                }
            }
        }
        if (CollectionUtils.isEmpty(rightIds)) {
            return;
        }
        Role roleFromDb = roleMapper.selectByPrimaryKey(id);
        if (roleFromDb == null) {
            return;
        }
        String authIdsFromDb = roleFromDb.getAuthIds();
        if (StringUtils.isBlank(authIdsFromDb) && authIdsFromDb.equalsIgnoreCase(",")) {
            return;
        }

        StringBuilder sb = new StringBuilder();
        for (String authId : authIdsFromDb.split(",")) {
            if(StringUtils.isBlank(authId) || rightIds.contains(Integer.parseInt(authId))){
                continue;
            }
            sb.append(",").append(authId);
        }

        Role role = new Role();
        role.setId(id);
        role.setAuthIds(StringUtils.isBlank(sb.toString()) ? "," : sb.toString());
        roleMapper.updateByPrimaryKeySelective(role);
    }

    public void delete(Integer id) {
        roleMapper.deleteByPrimaryKey(id);
    }

    public void update(Role role) {
        role.setAuthIds(null);
        roleMapper.updateByPrimaryKeySelective(role);
    }

    public void add(Role role) {
        Role role4Name = new Role();
        role4Name.setRoleName(role.getRoleName());
        if(roleMapper.selectOne(role4Name) != null){
            throw new BussinessException(HttpStatus.BAD_REQUEST.value(), ResultConst.ROLE_NAME_EXIST);
        }
        role.setAuthIds(null);
        role.setId(null);
        roleMapper.insertSelective(role);
    }

    private void getRightIdsByPermMo(PermissionRespMo permissionRespMo, Set<Integer> rightIds){
        // level one
        rightIds.add(permissionRespMo.id);
        if (CollectionUtils.isNotEmpty(permissionRespMo.children)) {
            for (PermissionRespMo child : permissionRespMo.children) {
                // level two
                rightIds.add(child.id);
                if (CollectionUtils.isNotEmpty(child.children)) {
                    for (PermissionRespMo respMo : child.children) {
                        // level three
                        rightIds.add(respMo.id);
                    }
                }
            }
        }
    }

    private List<RolePermissionRespMo> buildRolePerm(Integer id) {
        List<RolePermissionRespMo> rolePermissionRespMos = new ArrayList<>();
        List<Role> roles;
        if (id == null) {
            roles = roleMapper.selectAll();
        } else {
            roles = new ArrayList<>();
            roles.add(roleMapper.selectByPrimaryKey(id));
        }
        if (CollectionUtils.isNotEmpty(roles)) {
            Map<Integer, Permission> permMap = new HashMap<>();
            List<Permission> permList = permissionCache.getPermList();
            for (Permission perm : permList) {
                permMap.put(perm.getId(), perm);
            }
            for (Role role : roles) {
                RolePermissionRespMo mo = new RolePermissionRespMo();
                mo.id = role.getId();
                mo.roleName = role.getRoleName();
                mo.roleDesc = role.getRoleDesc();

                String authIds = role.getAuthIds();
                if (StringUtils.isNotBlank(authIds) && !authIds.equalsIgnoreCase(",")) {
                    List<Permission> rolePermList = new ArrayList<>();
                    for (String rolePerm : authIds.split(",")) {
                        if (StringUtils.isNotBlank(rolePerm.trim())) {
                            rolePermList.add(permMap.get(Integer.parseInt(rolePerm)));
                        }
                    }
                    rolePermList.sort(Comparator.comparingInt(Permission::getLevel));
                    mo.children = permissionCache.buildTreePerms(rolePermList);
                }
                rolePermissionRespMos.add(mo);
            }
        }
        return rolePermissionRespMos;
    }

}
